export default function execGraph(graphData) {
  const cells = graphData["cells"];
  const nodes = getNodes(cells);
  const nodeByIdMap = genNodeMap(nodes);
  const [edgeBySourceIdMap, edgeByTargetIdMap] = getEdges(cells);
  // 队列 queue，可执行表
  const canExecTable = [];
  // const executedTable = new Map();
  // const waitDetectTable = []; // 待检测表
  initCanExecTable();

  while (canExecTable.length) {
    // 取出 canExecTable 中的第一个节点
    const node = canExecTable.shift();
    // 执行，获得执行结果
    const paramRes = execNode(node);
    // const paramName = node.data.outArr[0]["paramName"];
    node.data.outArr[0]["paramRes"] = paramRes;
    const edges = edgeBySourceIdMap.get(node.id);
    edges.forEach((edge) => {
      const node = nodeByIdMap.get(edge.target.cell);
      const paramName = edge.target.port;
      // 更新参数
      node.data.inArr.forEach((inParam) => {
        if (inParam["paramName"] === paramName) {
          inParam["paramRes"] = paramRes;
        }
      });
      // 更新 canExecTable
      if (canExec(node)) {
        console.log(node.data.inArr);
        canExecTable.push(node);
      }
    });
  }
  // console.log(nodes[nodes.length - 1].data.outArr)
  return graphData;

  function getNodes(cells) {
    let nodes = [];
    cells.forEach((cell) => {
      if (!cell.source) {
        // const id = cell.id;
        // const name = cell.data.name;
        // const inPorts = cell.data.inArr;
        // const outPorts = cell.data.outArr;
        // nodes.push(new X6Node(id, name, inPorts, outPorts));
        nodes.push(cell);
      }
    });
    return nodes;
  }

  function genNodeMap(nodes) {
    const nodeByIdMap = new Map();
    nodes.forEach((node) => {
      const id = node.id;
      nodeByIdMap.set(id, node);
    });
    return nodeByIdMap;
  }

  function getEdges(cells) {
    let edgeBySourceIdMap = new Map();
    let edgeByTargetIdMap = new Map();
    const nodes = getNodes(cells);
    // 构建邻接表
    nodes.forEach((node) => {
      const id = node.id;
      edgeBySourceIdMap.set(id, []);
      edgeByTargetIdMap.set(id, []);
    });
    cells.forEach((cell) => {
      if (cell.source) {
        const sourceId = cell.source.cell;
        const targetId = cell.target.cell;
        const sourceEdges = edgeBySourceIdMap.get(sourceId);
        sourceEdges.push(cell);
        edgeBySourceIdMap.set(sourceId, sourceEdges);
        const targetEdges = edgeByTargetIdMap.get(targetId);
        targetEdges.push(cell);
        edgeByTargetIdMap.set(targetId, targetEdges);
      }
    });
    return [edgeBySourceIdMap, edgeByTargetIdMap];
  }

  function initCanExecTable() {
    edgeByTargetIdMap.forEach((edges, targetId) => {
      if (edges.length === 0) {
        canExecTable.push(nodeByIdMap.get(targetId));
      }
    });
  }

  function execNode(node) {
    let params = {};
    switch (node.data.name) {
      case "常数":
        console.log("static:", node.data.outArr[0].paramRes);
        return parseFloat(node.data.outArr[0].paramRes);
      case "ADD":
        params = {};
        node.data.inArr.forEach((inParam) => {
          params[inParam["paramName"]] = inParam["paramRes"];
        });
        console.log(
          `add: add1(${params["add1"]}) + add2(${params["add2"]}) = ${
            params["add1"] + params["add2"]
          }`
        );
        return params["add1"] + params["add2"];
      case "Minus":
        params = {};
        node.data.inArr.forEach((inParam) => {
          params[inParam["paramName"]] = inParam["paramRes"];
        });
        console.log(
          `minus: minus1(${params["minus1"]}) - minus2(${params["minus2"]}) = ${
            params["minus1"] - params["minus2"]
          }`
        );
        return params["minus1"] - params["minus2"];
      case "Mul":
        params = {};
        node.data.inArr.forEach((inParam) => {
          params[inParam["paramName"]] = inParam["paramRes"];
        });
        console.log(
          `mul: mul1(${params["mul1"]}) * mul2(${params["mul2"]}) = ${
            params["mul1"] * params["mul2"]
          }`
        );
        return params["mul1"] * params["mul2"];
      default:
        break;
    }
  }

  function canExec(node) {
    const inParams = node.data.inArr;
    for (let i = 0; i < inParams.length; i++) {
      const inParam = inParams[i];
      if (inParam["paramRes"] === undefined) {
        return false;
      }
    }
    return true;
  }
}
